package com.se.net;

import com.sun.jna.LastErrorException;
import com.sun.jna.WString;
import com.util.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.drasyl.channel.tun.TunAddress;
import org.drasyl.channel.tun.jna.TunDevice;
import org.drasyl.channel.tun.jna.windows.Guid;
import org.drasyl.channel.tun.jna.windows.WinDef;
import org.drasyl.channel.tun.jna.windows.WindowsTunDevice;
import org.drasyl.channel.tun.jna.windows.Wintun;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;

import static org.drasyl.channel.tun.jna.windows.Wintun.*;

/**
 * @author hdu_huang
 * @since 2024/3/6 10:10
 *  jna-platform-5.14.0.jar   iphlpapi.h   操作网卡, IP, DNS等
 *  GetExtendedTcpTable/GetExtendedUdpTable 获取TCP/UDP连接信息,包含PID netstat -anp tcp/udp    基于源地址策略路由
 */
@Slf4j
public class NetUtil {

    //wintun properties
    public static final int ERROR_NO_MORE_ITEMS = 259;
    public static final int WINTUN_MIN_RING_CAPACITY = 0x20000;
    public static final int WINTUN_MAX_RING_CAPACITY = 0x4000000;

    private static final byte[] guidBytes ={53, 69, -7, -87, -100, 28, 64, -66, -90, 59, 11, -7, 113, -14, -2, 56};

    //确保GUID一样，这样每次wintun生成的adapter都是一样的
    public static Guid.GUID GUID = Guid.GUID.fromBinary(guidBytes);
    public static final WString TUNNEL_TYPE = new WString("huang");

    public static WindowsTunDevice openTunDevice(String name){
        if (name == null) {
            name = "tun";
        }

        TunAddress tunAddress = new TunAddress(name);
        Wintun.WINTUN_ADAPTER_HANDLE adapter = null;
        Wintun.WINTUN_SESSION_HANDLE session = null;
        try {
            adapter = WintunCreateAdapter(new WString(name), TUNNEL_TYPE, GUID);
            session = WintunStartSession(adapter, new WinDef.DWORD(0x400000));
        }
        catch (LastErrorException e) {

            if (adapter != null) {
                WintunCloseAdapter(adapter);
            }

            log.error("open wintun adapter error", e);
            throw new Error(e);

        }

        Constructor<?> constructor = BeanUtils.getDeclaredConstructor(WindowsTunDevice.class, Wintun.WINTUN_ADAPTER_HANDLE.class, Wintun.WINTUN_SESSION_HANDLE.class, TunAddress.class);
        Object o = BeanUtils.newInstance(constructor, adapter, session, tunAddress);

        return (WindowsTunDevice) o;
    }


    public static List<String> query(String command) throws Exception {
        Process process = exec(command.split(" "));
        process.waitFor();
        List<String> lines = new ArrayList<>();
        String line;
        //GBK兼容GB2312
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) {
            while (null != (line = reader.readLine())) {
                lines.add(line);
            }
        }
        return lines;
    }

    public static int exec(String command) throws Exception {
        return exec(command.split(" ")).waitFor();
    }

    public static Process exec(String... command) throws Exception {
        return new ProcessBuilder(command).redirectErrorStream(true).start();
    }


    //# 创建原始套接字 int sockfd = socket(AF_PACKET, SOCK_RAW, htons(ETH_P_ALL));   发送以太包

    //netsh interface ipv4 set address name="myselfTun" source=static address=198.18.1.1  mask=255.255.255.0 gateway=198.18.1.1
    public static void main(String[] args) throws Exception{

        //var tunName = "testTun";
        long begin = System.currentTimeMillis();
        //TunDevice tunDevice = openTunDevice("testTun");

        //netsh interface ip show config name=testTun
        //List<String> netshInterfaceShowInterface = query("netsh interface show interface");

        long begin1 = System.currentTimeMillis();

        String command = "netsh interface ip set address name=testTun source=static 198.18.1.1/24  gateway=none";
        String command1 = "netsh interface ip set dns testTun static 198.18.1.2 primary";
        String command2 = "wmic process get processid,name,executablepath";
        //int result = exec(command);
        //int result1 = exec(command1);

        //List<String> netshInterfaceShowInterface = query(command2);

        //!设置ip别名
        //exec("netsh interface ip add address name=testTun addr=10.10.0.21 mask=255.255.0.0");

        long begin2 = System.currentTimeMillis();

        long use1 = begin1 - begin;
        long use2 = begin2 - begin1;

        System.out.println("use time:" + use1 + "ms" + " " + use2 + "ms");

        System.in.read();
        //tunDevice.close();
        Thread.sleep(1000);

    }

}
